iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
AI Engineering

從零打造情感感知 Agentic System:FSM 狀態機與 RAG 的整合實作系列 第 8 篇

Day 08:【意圖路由】AI 也懂看眼色?打造 Intent Router 讓 Agent 聰明分流

  • 分享至 

  • xImage
  •  

介紹

前七天,我們的Agent已經具備了傲嬌靈魂與長期記憶。但如果今天使用者不只是想跟她談戀愛(?),而是希望她幫忙「寫程式」、「算數」或「查資料」時...

如果在那邊:「哼!15 乘 32 等於多少我才不告訴你呢!笨蛋!」,這不叫傲嬌,這叫「無效溝通」啊!

為了讓 AI 在陪伴使用者的同時,又能隨時「切換成專業工作模式」,我們需要一個像是《刀劍神域》SYSTEM 控制權一樣的「大腦總機」,Intent Router(意圖路由器)!

今天的輕量任務:

  1. 搞懂什麼是 Intent Router
  2. 建立獨立的路由判斷模組 (router.py)
  3. 讓 AI 自動判斷你是想「純閒聊」還是要「正經解任務」!

第一關:什麼是 Intent Router?(AI 的眼力測驗)

簡單來說,Intent Router 就像是動漫裡的「總部指揮中心」:

  • 使用者傳訊息進來時,Router 會先在背後偷偷發動「心靈掃描」。
  • 判斷這句話屬於什麼屬性(例如:CHAT 日常閒聊 / 觸發好感度,TASK 啟動作戰模式 / 認真解任務)。
  • 根據分類結果,決定是要讓 Agent 發動「傲嬌吐槽」,還是切換成「冷酷高效」的任務處理模式!

第二關:打造路由模組 (router.py)

我們利用 Gemini 輕量且極速的特性,撰寫一個專門用來「讀空氣」的分類器。

在專案目錄下新增 router.py:

from google import genai
from google.genai import types

ROUTER_SYSTEM_INSTRUCTION = """
你是一個精準的意圖分類器(警戒雷達)。請分析使用者的輸入,並嚴格只回傳以下其中一個標籤:

- CHAT:當使用者在打招呼、日常閒聊、開玩笑、感情諮詢、誇獎莉莉或進行角色互動時。
- TASK:當使用者提出明確的具體任務,例如要莉莉計算數學、寫代碼、翻譯文本、查詢資料或解決課業問題時。
"""

def classify_intent(client: genai.Client, user_input: str) -> str:
    response = client.models.generate_content(
        model='gemini-3.6-flash',
        contents=user_input,
        config=types.GenerateContentConfig(
            system_instruction=ROUTER_SYSTEM_INSTRUCTION,
            temperature=0.0,
        )
    )
    # response.text 在模型回空字串、或被 safety filter 擋掉時會是 None,
    # 直接 .strip() 會 AttributeError,所以用 or "" 墊底
    intent = (response.text or "").strip().upper()

    # 分不出來就一律當閒聊:誤判成 CHAT 只是回得傲嬌一點,
    # 誤判成 TASK 會讓角色突然變成客服,體驗差得多
    return intent if intent in ["CHAT", "TASK"] else "CHAT"

第三關:在 app.py 裝上「看眼色」的雷達

別忘了在檔案頂部引入剛剛寫好的router模組:

import router

打開我們的 app.py,在呼叫 Agent 回應前,先讓 Router 進行判斷

try:
    # 先發動意圖雷達判斷 (CHAT 或 TASK)
    intent = router.classify_intent(client, user_input)

    if intent == "CHAT":
        # 走原本的莉莉傲嬌日常聊天路線
        response = st.session_state.chat.send_message(user_input)
        ai_reply = response.text
    else:
        # 切換成工作模式
        # 這裡照樣用 send_message,只是用 config 覆寫這一輪的人設,
        # 目的是讓這一輪仍然留在 chat 的 history 裡。
        response = st.session_state.chat.send_message(
            user_input,
            config=types.GenerateContentConfig(
                system_instruction="請以極度精準、高效率的方式完成使用者的任務,不要有任何傲嬌廢話或角色扮演。"
            )
        )
        ai_reply = f"(哼!這種正經事就交給我吧)\n\n{response.text}"

except Exception as e:
    # 這一輪完全不落地:session 和 Firestore 都維持送出前的狀態
    st.error(f"角色沒有回應,API 出錯了:{e}")
    st.info("這句話沒有被記錄,重新整理後會消失,可以直接再說一次。")
    st.stop()

# 顯示 AI 角色的回應
with st.chat_message("assistant", avatar=AI_AVATAR):
    st.write(ai_reply)

# 確定有回應了,才把這一輪的兩筆訊息一起存入 Session 與 Firestore
st.session_state.messages.append({"role": "user", "content": user_input})
save_message(st.session_state.user_id, "user", user_input)

st.session_state.messages.append({"role": "assistant", "content": ai_reply})
save_message(st.session_state.user_id, "assistant", ai_reply)

第四關:實測分流魔法!

  • 日常閒聊:「莉莉你今天心情好嗎?」
    • MAGI 判斷:CHAT
    • 莉莉回應:「哼!關你什麼事啊?我心情好不好才不用跟你報告呢!……不過,如果你今天乖乖不惹我生氣的話,說不定會稍微好那麼一點點啦!笨蛋!」(傲嬌屬性全開)
      https://ithelp.ithome.com.tw/upload/images/20260922/201838770lmZNcVV7W.png
  • 認真任務:「莉莉,我考妳 415411 * 114514 是多少」
    • MAGI 判斷:TASK
    • 莉莉回應:「(哼!這種正經事就交給我吧:計算結果為:47,570,375,254(四百七十五億七千零三十七萬五千二百五十四)」
      https://ithelp.ithome.com.tw/upload/images/20260922/201838778FxHU57wm2.png

上一篇
Day 07:【靈魂注入2】Few-Shot Prompting!手把手教角色學會極致吐槽與口癖
下一篇
Day 09:【好感度系統1】暴走列車如何啟動?有限狀態機 ( FSM 理論篇)
系列文
從零打造情感感知 Agentic System:FSM 狀態機與 RAG 的整合實作 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言